use thiserror::Error;

/// 下载错误类型
#[derive(Error, Debug, Clone)]
pub enum DownloadError {
    #[error("网络请求失败: {0}")]
    Network(String),
    #[error("IO 错误: {0}")]
    Io(String),
    #[error("URL 解析错误: {0}")]
    Url(String),
    #[error("无效的 m3u8 格式")]
    InvalidM3u8,
    #[error("没有找到视频分片")]
    NoSegments,
    #[error("配置错误: {0}")]
    Config(String),
    #[error("转换错误: {0}")]
    Conversion(String),
}

impl From<reqwest::Error> for DownloadError {
    fn from(err: reqwest::Error) -> Self {
        DownloadError::Network(err.to_string())
    }
}

impl From<std::io::Error> for DownloadError {
    fn from(err: std::io::Error) -> Self {
        DownloadError::Io(err.to_string())
    }
}

impl From<url::ParseError> for DownloadError {
    fn from(err: url::ParseError) -> Self {
        DownloadError::Url(err.to_string())
    }
}

/// 结果类型别名
pub type DownloadResult<T> = Result<T, DownloadError>;

#[cfg(test)]
mod tests {
    use super::*;
    use std::io;

    #[test]
    fn test_download_error_from_reqwest_error() {
        // 模拟 reqwest 错误转换
        let error_msg = "网络连接失败";
        let download_error = DownloadError::Network(error_msg.to_string());
        
        assert!(matches!(download_error, DownloadError::Network(_)));
        assert_eq!(download_error.to_string(), format!("网络请求失败: {error_msg}"));
    }

    #[test]
    fn test_download_error_from_io_error() {
        // 测试 IO 错误转换
        let io_error = io::Error::new(io::ErrorKind::NotFound, "文件不存在");
        let download_error = DownloadError::from(io_error);
        
        assert!(matches!(download_error, DownloadError::Io(_)));
        assert!(download_error.to_string().contains("IO 错误"));
        assert!(download_error.to_string().contains("文件不存在"));
    }

    #[test]
    fn test_download_error_from_url_parse_error() {
        // 测试 URL 解析错误
        let url_result = url::Url::parse("invalid-url");
        assert!(url_result.is_err());
        
        let download_error = DownloadError::from(url_result.unwrap_err());
        assert!(matches!(download_error, DownloadError::Url(_)));
        assert!(download_error.to_string().contains("URL 解析错误"));
    }

    #[test]
    fn test_download_error_variants() {
        // 测试所有错误变体
        let errors = vec![
            DownloadError::Network("网络错误".to_string()),
            DownloadError::Io("IO错误".to_string()),
            DownloadError::Url("URL错误".to_string()),
            DownloadError::InvalidM3u8,
            DownloadError::NoSegments,
            DownloadError::Config("配置错误".to_string()),
            DownloadError::Conversion("转换错误".to_string()),
        ];

        for error in errors {
            // 确保每个错误都能正确显示
            assert!(!error.to_string().is_empty());
            
            // 测试错误的 Debug 格式
            assert!(!format!("{error:?}").is_empty());
        }
    }

    #[test]
    fn test_download_error_clone() {
        // 测试错误类型可以被克隆
        let original = DownloadError::Network("原始错误".to_string());
        let cloned = original.clone();
        
        assert_eq!(original.to_string(), cloned.to_string());
    }

    #[test]
    fn test_download_result_type_alias() {
        // 测试 DownloadResult 类型别名
        let success_result: DownloadResult<i32> = Ok(42);
        let error_result: DownloadResult<i32> = Err(DownloadError::InvalidM3u8);
        
        assert!(success_result.is_ok());
        if let Ok(value) = success_result {
            assert_eq!(value, 42);
        }
        
        assert!(error_result.is_err());
        if let Err(error) = error_result {
            assert!(matches!(error, DownloadError::InvalidM3u8));
        }
    }
}